import store from '../store';
import {
	PYTHON_URL,
	BASE_URL,
	ENV_CONFIG
} from '@/config/request.js';
import {
	OrderApi,
	PrintApi
} from '@/api';

/**
 * 节流函数
 * 思路： 第一次先设定一个变量true,
 * 第二次执行这个函数时，会判断变量是否true,
 * 是则返回。当第一次的定时器执行完函数最后会设定变量为flase。
 * 那么下次判断变量时则为flase，函数会依次运行。
 */
const throttle = (fn, delay = 100) => {
	// 首先设定一个变量，在没有执行我们的定时器时为null
	var timer = null
	return function() {
		// 当我们发现这个定时器存在时，则表示定时器已经在运行中，需要返回
		if (timer) return
		timer = setTimeout(() => {
			fn.apply(this, arguments)
			timer = null
		}, delay)
	}
}

/**
 * 防抖函数
 * 首次运行时把定时器赋值给一个变量， 第二次执行时，
 * 如果间隔没超过定时器设定的时间则会清除掉定时器，
 * 重新设定定时器， 依次反复， 当我们停止下来时，
 * 没有执行清除定时器， 超过一定时间后触发回调函数。z
 */
const debounce = (fn, delay) => {
	let timer
	return function() {
		const that = this
		const _args = arguments // 存一下传入的参数
		if (timer) {
			clearTimeout(timer)
		}
		timer = setTimeout(function() {
			fn.apply(that, _args)
		}, delay)
	}
}

/**
 * @param {Object | String} opt
 * @param {Object | String} toUrl
 * 例:
 * this.Tips('/pages/test/test'); 跳转不提示
 * this.Tips({title:'提示'},'/pages/test/test'); 提示并跳转
 * this.Tips({title:'提示'},{tab:1,url:'/pages/index/index'}); 提示并跳转值table上
 * tab=1 一定时间后跳转至 table上
 * tab=2 一定时间后跳转至非 table上
 * tab=3 一定时间后返回上页面
 * tab=4 关闭所有页面，打开到应用内的某个页面
 * tab=5 关闭当前页面，跳转到应用内的某个页面
 */
const Tips = (opt, toUrl) => {
	if (typeof opt == 'string') {
		toUrl = opt;
		opt = {};
	}
	let title = opt.title || '',
		icon = opt.icon || 'none',
		endtime = opt.endtime || 2000,
		success = opt.success;
	if (title) uni.showToast({
		title: title,
		icon: icon,
		duration: endtime,
		success
	})
	if (toUrl != undefined) {
		if (typeof toUrl == 'object') {
			let tab = toUrl.tab || 1,
				url = toUrl.url || '';
			switch (tab) {
				case 1:
					//一定时间后跳转至 table
					setTimeout(function() {
						uni.switchTab({
							url: url
						})
					}, endtime);
					break;
				case 2:
					//跳转至非table页面
					setTimeout(function() {
						uni.navigateTo({
							url: url,
						})
					}, endtime);
					break;
				case 3:
					//返回上页面
					setTimeout(function() {
						uni.navigateBack({
							delta: parseInt(url),
						})
					}, endtime);
					break;
				case 4:
					//关闭所有页面，打开到应用内的某个页面
					setTimeout(function() {
						uni.reLaunch({
							url: url,
						})
					}, endtime);
					break;
				case 5:
					//关闭当前页面，跳转到应用内的某个页面
					setTimeout(function() {
						uni.redirectTo({
							url: url,
						})
					}, endtime);
					break;
			}

		} else if (typeof toUrl == 'function') {
			setTimeout(function() {
				toUrl && toUrl();
			}, endtime);
		} else {
			//没有提示时跳转不延迟
			setTimeout(function() {
				uni.navigateTo({
					url: toUrl,
				})
			}, title ? endtime : 0);
		}
	}
}

/**
 * 是否数组
 * @param {Array} array 数组
 */
const isArray = (array) => {
	return Object.prototype.toString.call(array) === '[object Array]'
}

/**
 * 是否对象
 * @param {*} obj 对象
 * @returns
 */
const isObject = (obj) => {
	return Object.prototype.toString.call(obj) === '[object Object]'
}

/**
 * 是否在数组内
 * @param {*} search 搜寻对象
 * @param {Array} array 寻找数组
 */
const inArray = (search, array) => {
	for (var i in array) {
		if (array[i] == search) return true
	}
	return false
}

/**
 * 判断是否为空
 * @param {*} value 源对象
 */
const isEmpty = (value) => {
	if (isArray(value)) {
		return value.length === 0
	}
	if (isObject(value)) {
		return isEmptyObject(value)
	}
	return !value
}

/**
 * 判断是否为空对象
 * @param {*} object 源对象
 */
const isEmptyObject = (object) => {
	return Object.keys(object).length === 0
}

/**
 * 对象转URL
 * @param {Object} obj
 */
const urlEncode = function(obj = {}) {
	const result = []
	for (const key in obj) {
		const item = obj[key]
		if (!item) {
			continue
		}
		if (isArray(item)) {
			item.forEach(val => {
				result.push(key + '=' + val)
			})
		} else {
			result.push(key + '=' + item)
		}
	}
	return result.join('&')
}

/**
 * 对象深拷贝
 * @param {*} obj 源对象
 */
const cloneObj = (obj) => {
	let newObj = obj.constructor === Array ? [] : {};
	if (typeof obj !== 'object') {
		return;
	}
	for (let i in obj) {
		newObj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
	}
	return newObj
}


/**
 * 显示成功提示框
 * @param {String} msg 提示文本  
 * @param {Function} callback 使用成功回调
 */
const showSuccess = (msg, callback) => {
	uni.showToast({
		title: msg,
		icon: 'success',
		mask: true,
		duration: 1500,
		success() {
			callback && callback()
		}
	})
}

/**
 * 显示纯文字提示框
 * @param {String} msg 提示文本
 * @param {Number} duration 延迟时间    
 * @param {Boolean} mask 遮罩层 
 */
const showToast = (msg, duration = 1500, mask = false) => {
	uni.showToast({
		title: msg, // 提示的内容
		icon: 'none',
		mask, // 是否显示透明蒙层，防止触摸穿透
		duration // 提示的延迟时间，单位毫秒，默认：1500
	})
}

/**
 * tabBar页面路径列表 (用于链接跳转时判断)
 * tabBarLinks为常量, 无需修改
 * @returns tabBarLinks = [...页面路径]
 */
export const getTabBarLinks = () => {
	const tabBarLinks = [
		'pages/index/index',
		'pages/user/index',
	]
	return tabBarLinks
}

/**
 * 跳转到指定页面url
 * 支持tabBar页面
 * @param {String}  url   页面路径
 * @param {Object}  query 页面参数
 * @param {String}  mode  跳转类型(默认navigateTo)
 */
const navTo = (url, query = {}, mode = 'navigateTo') => {
	if (!url || url.length == 0) {
		return false
	}
	// tabBar页面, 使用switchTab
	if (inArray(url, getTabBarLinks())) {
		uni.switchTab({
			url: `/${url}`
		})
		return true
	}
	// 生成query参数
	const queryStr = !isEmpty(query) ? '?' + urlEncode(query) : ''
	// 普通页面, 使用navigateTo
	mode === 'navigateTo' && uni.navigateTo({
		url: `/${url}${queryStr}`
	})
	// 特殊指定, 使用redirectTo
	mode === 'redirectTo' && uni.redirectTo({
		url: `/${url}${queryStr}`
	})
	return true
}

/**
 * 获取更多列表数据
 * @return {Array} list
 */
const getEmptyPaginateObj = () => {
	return cloneObj(paginate)
}

/**
 * 加载更多列表数据
 * @param {Object} resList 新列表
 * @param {Object} oldList 旧列表数据
 * @param {int} pageNo 当前页码
 */
const getMoreListData = (resList, oldList, pageNo) => {
	// 如果是第一页需手动制空列表
	if (pageNo == 1) oldList.data = []
	// 合并新数据
	return oldList.data.concat(resList.data)
}

/**
 * 加载中提示
 * @param {Object} config 配置项
 */
const showLoading = (config) => {
	uni.showLoading({
		title: '加载中...',
		mask: true,
		duration: 60000,
		...config
	})
}


/** 上传文件
 * @param {File} file  
 * @param {Boolean} isPython 是否使用本地 python 接口  
 */
function uploadFile(file, isPython = true) {
	return new Promise((resolve, reject) => {
		uni.uploadFile({
			url: isPython && ENV_CONFIG ? PYTHON_URL + `/upload` : BASE_URL + 'mini/ApiConnect/upload',
			filePath: file.path || file.url || file,
			name: 'file',
			header: {},
			formData: {
				"user_id": store.getters.userInfo.user_id,
				"file_name": file.name || file.filename || ''
			},
			success: (res) => {
				const data = JSON.parse(res.data);
				if (data.code === 200 || data.status === 1) {
					return resolve({
						result: data.result
					});
				} else {
					return reject(data.msg);
				}
			},
			fail: (err) => {
				console.log(err);
				return reject('上传请求失败');
			}
		});
	});
}

// 是否文档文件
function isDocumentType(fileName = '') {
	const Reg = new RegExp(/\.((pdf|ppt|pptx|doc|docx))$/i)
	return Reg.test(fileName)
}

// 是否图片文件
function isImage(fileName = '') {
	const Reg = new RegExp(/\.((jpeg|jpg|png|gif|svg|psd|gif|TIFF|webp|EPS))$/i)
	return Reg.test(fileName)
}

/**
 * 是否跳转登录
 */
function whetherToLogin() {
	if (!store.getters['token'])
		return navTo('pages/mines/login')
}

/**
 * 从微信选择上传
 * @param {Number} type 允许选择什么文件类型 
 * @param {Number} count 选择数量 
 * @return {Array} 上传后的文件列表 {type:"文件类型", file:"文件地址", pageRange:"页码范围"}
 */
function uploadWechat(type, count = 10) {
	return new Promise(async (resolve, reject) => {
		try {
			const res = await toPromise(wx.chooseMessageFile, {
				count,
				type,
			})
			let fileList = []
			if (type === 'file') {
				res.tempFiles.forEach(item => {
					if (!isDocumentType(item.name)) {
						if (res.tempFiles.length === 1)
							return reject(new Error(`无法上传${item.name.split('.')[item.name.split('.').length - 1]}类型的文件`))
					} else {
						fileList.push(item)
					}
				})
			} else if (type === 'image') {
				fileList = res.tempFiles
			}
			return resolve({
				errNum: res.tempFiles.length - fileList.length, // 上传错误的数量
				fileList
			})
		} catch (err) {
			console.log('上传失败= ', err);
			return reject(err)
		}
	})
}

/**
 * 从相册选择上传
 */
function uploadImage(count = 10) {
	return new Promise(async (resolve, reject) => {
		try {
			const res = await toPromise(uni.chooseImage, {
				sizeType: ['original', 'compressed'],
				sourceType: ['album'],
				count,
			})
			return resolve({
				errNum: 0, // 上传错误的数量
				fileList: res.tempFiles
			})
		} catch (err) {
			console.log('上传失败= ', err);
			return reject(err)
		}
	})
}

/**
 * 从腾讯文档选择上传
 */
function uploadTxDoc() {
	// #ifdef MP-WEIXIN
	wx.navigateToMiniProgram({
		appId: 'wxd45c635d754dbf59',
		path: 'pages/detail/detail?url=' + encodeURIComponent('https://docs.qq.com/doc/DVmtlZUVtVGxQZFp3'),
	});
	// #endif
}

/**
 * 回调直接输出
 * @param {Function} fn uniapp的api组件
 * @param {Object} options 组件配置项
 */
const toPromise = (fn, options = {}) => new Promise((resolve, reject) => {
	fn({
		...options,
		success: (res) => resolve(res),
		fail: (err) => reject(err),
		complete: (err) => reject(err),
		cancel: (err) => reject(err),
	})
})

/**
 * 预览文件
 * @param {String} 文件地址 
 */
function previewFile(url) {
	showLoading()
	uni.downloadFile({
		url,
		success: (res) => {
			const filePath = res.tempFilePath;
			uni.openDocument({
				filePath,
				success: (res) => {},
				complete: () => {
					uni.hideLoading()
				}
			});
		},
		fail: () => {
			uni.hideLoading()
		}
	});
}

export {
	throttle,
	debounce,
	Tips,
	isArray,
	isObject,
	inArray,
	isEmpty,
	urlEncode,
	cloneObj,
	isEmptyObject,
	navTo,
	showToast,
	showLoading,
	uploadFile,
	uploadWechat,
	uploadImage,
	uploadTxDoc,
	whetherToLogin,
	toPromise,
	previewFile,
}